home *** CD-ROM | disk | FTP | other *** search
/ 3D GFX / 3D GFX.iso / amiutils / e_h / getilbm / getilbm.c < prev    next >
C/C++ Source or Header  |  1995-12-30  |  32KB  |  882 lines

  1. //===========================================================================
  2. // GETILBM.C  --  for AmigaDOS 2.0/3.0 (and maybe 1.3 with iffparse.library)
  3. // Rev: 30 September 1994, Alex Matulich  matulich_alex@SEAA.NAVSEA.NAVY.MIL
  4. //
  5. // For SAS C/C++ 6.xx.  Compile with IGNORE=51 to disable warnings for
  6. // C++ comments (I got addicted to those C++ comments...)
  7. //
  8. // This module is for loading IFF ILBM pictures.  The *only* functions you
  9. // need to call are loadilbmScreen() and freeilbmScreen(), or if you are
  10. // just loading into bitmaps, call loadilbmBitMap() and freeBitMap().
  11. //
  12. // The iffparse.library must be opened prior to calling these routines.
  13. // SAS C 6.xx does this automatically for you.
  14. //
  15. // This module was adapted from the confusing plethora of functions in the
  16. // Amiga Developer's package for AmigaDOS 3.1.  All adaptations and excerpts
  17. // are indicated in the comments.
  18. //===========================================================================
  19.  
  20.  
  21. //---------------------------------------------------------------------------
  22. // To make the demo ILBM file reader, compile with only the symbol DEMO
  23. // defined.  Example:  sc optimize optsize def=DEMO link getilbm.c
  24. //
  25. // You might have your own versions of getBitMap() and freeBitMap() external
  26. // to this module (I do, for example, in my video buffering module).  If so,
  27. // then make sure the following two #defines are commented out.  If you wish
  28. // to use the getBitMap() and freeBitMap() functions contained in this
  29. // module, then uncomment the following two #defines.
  30.  
  31. // #define USE_GETBM    // comment out if you already have a getBitMap()
  32. // #define USE_FREEBM   // comment out if you already have a freeBitMap()
  33.  
  34. // These functions, if external, should be compatible with the prototypes
  35. // in getilbm_proto.h.
  36. //
  37. // Defining TIMECHECK enables calls to a user-supplied external function
  38. // check_for_switch() while the IFF file is loading.  The purpose of this
  39. // function is to allow the program to do time-critical things while a
  40. // large ILBM file is loading.  Sort of a pseudo-multitasking technique.
  41.  
  42. // #define TIMECHECK    // only if you need a check_for_switch() function
  43.  
  44. // Often it is more useful to simply load an IFF file into a bitmap, rather
  45. // than create a whole screen for it.  If you want to do just this, and you
  46. // never need to load an IFF file into a screen, then uncomment this line:
  47.  
  48. // #define NOILBMSCREEN  // only compile loadilbmBitMap() and associates
  49.  
  50. // This will cause the functions loadilbmScreen() and associated functions
  51. // and declarations to be skipped during compililation.
  52. //
  53. // Conversely, if you don't need loadilbmBitMap(), but only loadilbmScreen(),
  54. // then uncomment this line:
  55. //
  56. // #define ILBMSCREENONLY  // only compile loadilbmScreen() and associates
  57. //
  58. // The existence of getBitMap() and freeBitMap() are still controlled by
  59. // USE_GETBM and USE_FREEBM.
  60. // Do not define both NOILBMSCREEN and ILBMSCREENONLY at the same time.
  61. // Do not define either of them if you need *both* loadilbmScreen() and
  62. // loadilbmBitMap().
  63. //---------------------------------------------------------------------------
  64.  
  65. #ifdef NOTIMECHECK  // for compatibility with previous versions
  66.    #undef TIMECHECK
  67. #endif
  68.  
  69. #ifdef DEMO         // re-set definitions if compiling the demo
  70.    #ifdef USE_GETBM
  71.       #undef USE_GETBM          // demo doesn't need getBitMap()
  72.    #endif
  73.    #ifdef USE_FREEBM
  74.       #undef USE_FREEBM         // demo doesn't need freeBitMap()
  75.    #endif
  76.    #ifdef TIMECHECK
  77.       #undef TIMECHECK          // demo doesn't need check_for_switch()
  78.    #endif
  79.    #ifdef NOILBMSCREEN
  80.       #undef NOILBMSCREEN       // demo doesn't need loadilbmBitmap()
  81.    #endif
  82.    #ifndef ILBMSCREENONLY
  83.       #define ILBMSCREENONLY    // demo DOES need loadilbmScreen()
  84.    #endif
  85. #endif
  86.  
  87. #include <exec/memory.h>
  88. #include <exec/libraries.h>
  89. #include <graphics/gfx.h>
  90. #include <libraries/dos.h>
  91. #include <libraries/iffparse.h>
  92.  
  93. #include <proto/exec.h>
  94. #include <proto/graphics.h>
  95. #include <proto/dos.h>
  96. #include <proto/iffparse.h>
  97.  
  98. #ifndef NOILBMSCREEN
  99. #define USE_BUILTIN_MATH 1  // to use built-in min() and max() in string.h
  100. #include <string.h>
  101. #include <graphics/display.h>
  102. #include <intuition/intuition.h>
  103. #include <proto/intuition.h>
  104. #endif  // !NOILBMSCREEN
  105.  
  106. #include <stdlib.h>
  107.  
  108. #include "getilbm_proto.h"   // prototypes for user-callable functions
  109.  
  110. extern struct Library *IFFParseBase;
  111.  
  112.  
  113. // definitions from iffp/iff.h
  114.  
  115. #define ChunkMoreBytes(cn) (cn->cn_Size - cn->cn_Scan)
  116.  
  117. struct Chunk {
  118.    struct Chunk *ch_Next;
  119.    long ch_Type, ch_ID, ch_Size;
  120.    void *ch_Data;
  121.    };
  122.  
  123.  
  124. // definitions from iffp/ilbm.h
  125.  
  126. #define ID_ILBM  MAKE_ID('I','L','B','M')
  127. #define ID_BMHD  MAKE_ID('B','M','H','D')
  128. #define ID_CMAP  MAKE_ID('C','M','A','P')
  129. #define ID_BODY  MAKE_ID('B','O','D','Y')
  130. #define ID_CAMG  MAKE_ID('C','A','M','G')
  131.  
  132. // sizeof(a 3-byte structure) returns 16 due to word alignment, so we use:
  133. #define sizeofColorRegister 3
  134.  
  135. #define MAXAMDEPTH      8  // used for OS<V37, screen.c maxdisplaydepth(ID)
  136. #define MAXAMCOLORREG  32  // should use ViewPort->ColorMap.Count instead
  137.  
  138. #define RowBytes(w)        ((((w) + 15) >> 4) << 1)
  139. #define RowBits(w)         ((((w) + 15) >> 4) << 4)
  140.  
  141. #define mskNone      0  // masking techniques
  142. #define mskHasMask   1
  143. #define cmpNone      0  // compression techniques
  144. #define cmpByteRun1  1
  145.  
  146. typedef struct {
  147.    UWORD w, h;                  // raster width and height
  148.    WORD x, y;                   // pixel position for this image
  149.    UBYTE nPlanes, masking,      // # source bitplanes, masking (?)
  150.          compression, flags;    // compression, Commodore-defined flags
  151.    UWORD transparentColor;      // transparent color number (sort of)
  152.    UBYTE xAspect, yAspect;      // pixel aspect ratio width/height
  153.    WORD pageWidth, pageHeight;  // source page size in pixels
  154.    } BitMapHeader;
  155.  
  156. typedef struct { UBYTE red, green, blue; } ColorRegister;
  157. typedef struct { ULONG ViewModes; } CamgChunk;
  158.  
  159. #define BMHDB_CMAPOK 7
  160. #define BMHDF_CMAPOK (1 << BMHDB_CMAPOK)
  161.  
  162.  
  163. // from iffp/packer.h
  164. #define MaxPackedSize(rowsize) ((rowsize)+(((rowsize)+127)>>7))
  165.  
  166.  
  167. //---------------------------------------------------------------------------
  168. // Skip following five declarations if you don't need loadilbmScreen().
  169.  
  170. #ifndef NOILBMSCREEN
  171.  
  172. static UWORD __far ins_pens[] = { 0xffff }; // minimal pen definitions
  173.  
  174. long li_errcode;                      // error code returned by OpenScreen()
  175.  
  176. // You will want to expand the following tag list if you decide to
  177. // substitute OpenScreenTagList() for OpenScreen() in loadilbmScreen().
  178. // OpenScreen() works with all video modes, and is used here for
  179. // compatibility with AmigaDOS 1.3, just in case such an OS happens to
  180. // have a compatible iffparse.library.
  181.  
  182. static struct TagItem __far ins_ext[] = {
  183.    SA_DisplayID, 0L,                  // tag needed for display mode
  184.    SA_DClip, 0L,                      // needed for screen centering
  185.    SA_AutoScroll, TRUE,               // not really needed, but who cares?
  186.    SA_Pens, (ULONG)ins_pens,          // minimal tags needed for 2.0
  187.    SA_ErrorCode, (ULONG)&li_errcode,  // examine li_errcode for error codes
  188.    TAG_DONE
  189.    };
  190.  
  191. // Instead of opening a screen with functions specific to AmigaDOS 2.0,
  192. // we define an ExtNewScreen structure for use with OpenScreen() to
  193. // maintain compatibility with earlier OS versions.  The ins_ext[] taglist
  194. // above provides the enhancements necessary for OS 2.0 or greater.
  195.  
  196. static struct ExtNewScreen __far ins = {
  197.    0, 0, ~0, ~0,                      // left, top, width & height
  198.    2, 0, 1,                           // depth, DetailPen, BlockPen
  199.    0,                                 // ViewModes
  200.    CUSTOMSCREEN | SCREENQUIET | SCREENBEHIND | NS_EXTENDED,
  201.    NULL,                              // font
  202.    NULL, NULL, NULL,                  // title, gadgets, bitmap
  203.    ins_ext                            // tag extensions
  204.    };
  205.    
  206. static struct NewWindow __far inw = {
  207.    0, 0, ~0, ~0,                      // left, top, width, height
  208.    0, 1,                              // DetailPen, BlockPen
  209.    IDCMP_RAWKEY | IDCMP_VANILLAKEY,   // IDCMP flags (whatever you like)
  210.    SIMPLE_REFRESH | BORDERLESS | BACKDROP | NOCAREREFRESH,
  211.    NULL,                              // pointer to 1st user gadget
  212.    NULL,                              // pointer to user checkmark
  213.    NULL,                              // title
  214.    NULL,                              // pointer to window screen
  215.    NULL,                              // no superbitmap
  216.    100,100,100,100,                   // width & height, min & max
  217.    CUSTOMSCREEN
  218.    };
  219.  
  220. #endif  // !NOILBMSCREEN
  221.  
  222. //---------------------------------------------------------------------------
  223.  
  224. // internal prototypes
  225.  
  226. struct IFFHandle *getilbminfo(char *, USHORT *, USHORT *,
  227.                USHORT *, WORD **, USHORT *, unsigned long *, BitMapHeader **);
  228. void freeIFFHandle(struct IFFHandle *iff);
  229. int loadbody(struct IFFHandle *, struct BitMap *, BitMapHeader *);
  230. int loadbody2(struct IFFHandle *, struct BitMap *, BYTE *,
  231.               BitMapHeader *, BYTE *, ULONG);
  232. BOOL unpackrow(BYTE **pSource, BYTE **pDest, WORD srcBytes0, WORD dstBytes0);
  233.  
  234.  
  235. #ifdef DEMO
  236. //===========================================================================
  237. // DEMO main() FUNCTION
  238. // For demonstrating loadilbmScreen().
  239. //===========================================================================
  240. #include <stdio.h>
  241.  
  242. int main(int argc, char *argv[])
  243. {
  244. struct Screen *s;       // pointer to the screen that will be shown
  245. struct Message *msg;    // this is for trapping keystrokes
  246. int i = 0, err = 0;
  247.  
  248. if (argc < 2) {
  249.    fputs("ILBM Viewer\nNeeds filenames as commandline arguments.\n", stderr);
  250.    return err;
  251.    }
  252. fputs("Press any key to finish viewing an image.\n\n", stderr);
  253.  
  254. while (++i < argc) {                   // go thru all commandline arguments
  255.    fputs("loading ", stderr);          // display the filename being loaded
  256.    fputs(argv[i], stderr);
  257.    fflush(stderr);                     // make sure the name is displayed
  258.  
  259.    if (s = loadilbmScreen(argv[i])) {                 // load ILBM file
  260.       ScreenToFront(s);                               // show it if loaded
  261.       ActivateWindow(s->FirstWindow);                 // setup for keypress
  262.       Wait(1L<<s->FirstWindow->UserPort->mp_SigBit);  // wait for key
  263.       while (msg = GetMsg(s->FirstWindow->UserPort))  // clear msg buffer
  264.          ReplyMsg(msg);
  265.       freeilbmScreen(s, NULL);                        // close the screen
  266.       fputs("\n", stderr);
  267.       }                                               // go on to next file
  268.  
  269.    else {                                             // or report an error
  270.       fputs("... bad, incompatible, or nonexistent.\n", stderr);
  271.       ++err;
  272.       }
  273.    }
  274. return err;
  275. }
  276. //===========================================================================
  277. #endif // end of DEMO
  278.  
  279.  
  280. #ifndef NOILBMSCREEN  // ingore next 3 functions if NOILBMSCREEN is defined
  281.  
  282. //===========================================================================
  283. // CLIPIT -- called by loadilbmScreen() below
  284. // Adapted with minor changes from modules/screen.c
  285. //===========================================================================
  286. static void clipit(short wide, short high,
  287.             struct Rectangle *spos, struct Rectangle *dclip,
  288.             struct Rectangle *txto, struct Rectangle *stdo,
  289.             struct Rectangle *maxo, struct Rectangle *uclip, BOOL NoCenter)
  290. {
  291. struct Rectangle *besto;
  292. short minx, maxx, miny, maxy,
  293.       txtw, txth, stdw, stdh, bestw, besth;
  294.  
  295. // get txt, std, and max widths and heights
  296. txtw = txto->MaxX - txto->MinX + 1;
  297. txth = txto->MaxY - txto->MinY + 1;
  298. stdw = stdo->MaxX - stdo->MinX + 1;
  299. stdh = stdo->MaxY - stdo->MinY + 1;
  300.  
  301. if (wide <= txtw && high <= txth) {
  302.    besto = txto;
  303.    bestw = txtw;
  304.    besth = txth;
  305.    }
  306. else {
  307.    besto = stdo;
  308.    bestw = stdw;
  309.    besth = stdh;
  310.    }
  311.  
  312. if (uclip) {
  313.    *dclip = *uclip;
  314.    spos->MinX = uclip->MinX;
  315.    spos->MinY = uclip->MinY;
  316.    }
  317. else {
  318.    spos->MinX = minx = besto->MinX - ((wide - bestw) >> 1);
  319.    maxx = wide + minx - 1;
  320.    if (maxx > maxo->MaxX) maxx = maxo->MaxX;
  321.    if (minx < maxo->MinX) {
  322.       minx = maxo->MinX;
  323.       if (NoCenter) spos->MinX = minx;
  324.       }
  325.    miny = besto->MinY - ((high - besth) >> 1);
  326.    spos->MinY = miny = min(miny, txto->MinY);
  327.    maxy = high + miny - 1;
  328.    if (maxy > maxo->MaxY) maxy = maxo->MaxY;
  329.    if (miny < maxo->MinY) {
  330.       miny = maxo->MinY;
  331.       if (NoCenter) spos->MinY = miny;
  332.       }
  333.    dclip->MinX = minx;
  334.    dclip->MinY = miny;
  335.    dclip->MaxX = spos->MaxX = maxx;
  336.    dclip->MaxY = spos->MaxY = maxy;
  337.    }
  338. }
  339.  
  340.  
  341. //===========================================================================
  342. // LOADILBMSCREEN
  343. // Loads an IFF ILBM file into a bitmap and creates a custom screen to
  344. // display it, returning a pointer to the screen.  The screen is created
  345. // behind others; use ScreenToFront() to show, and freeilbmScreen() to
  346. // deallocate the screen.  If IFF ILBM file failed to load, NULL is returned
  347. // and the global long li_errcode is set as defined in <intuition/screens.h>:
  348. // (0):                    IFF ILBM file loaded, screen created successfully
  349. // (1) OSERR_NOMONITOR:    Monitor specification unavailable
  350. // (2) OSERR_NOCHIPS:      You need newer custom chips
  351. // (3) OSERR_NOMEM:        Insufficient normal RAM
  352. // (4) OSERR_NOCHIPMEM:    Insufficient chip RAM
  353. // (5) OSERR_PUBNOTUNIQUE: Public screen name already used
  354. // (6) OSERR_UNKNOWNMODE:  Unrecognized screen mode
  355. // (7) OSERR_TOODEEP:      Too many bitplanes in requested screen
  356. // (8) OSERR_ATTACHFAIL:   Failed to attach screens
  357. // (9) OSERR_NOTAVAILABLE: Mode unavailable for some other reason
  358. // other:                  Unknown error
  359. //===========================================================================
  360. struct Screen *loadilbmScreen(char *filename)
  361. {
  362. BitMapHeader *bmhd;
  363. struct Screen *iscr = NULL;
  364. struct Window *iwnd = NULL;
  365. USHORT wide, high, deep, colors = MAXAMCOLORREG, err = 0;
  366. WORD *colortable = NULL;
  367. unsigned long mode;
  368. struct Rectangle spos, dclip, txto, stdo, maxo;
  369. struct IFFHandle *iff = getilbminfo(filename, &wide, &high, &deep,
  370.                                     &colortable, &colors, &mode, &bmhd);
  371. if (!iff) return NULL;
  372. li_errcode = 0;
  373.  
  374. // The following if() block was adapted from modules/screen.c
  375. if ( ((struct Library *)GfxBase)->lib_Version >= 36) {
  376.    if (li_errcode = ModeNotAvailable(mode))
  377.       goto lis_done;
  378.    else {
  379.       QueryOverscan(mode, &txto, OSCAN_TEXT);
  380.       QueryOverscan(mode, &stdo, OSCAN_STANDARD);
  381.       QueryOverscan(mode, &maxo, OSCAN_MAX);
  382.       }
  383.    clipit(wide, high, &spos, &dclip, &txto, &stdo, &maxo, NULL, FALSE);
  384.    }
  385. else spos.MinX = spos.MinY = 0;
  386.  
  387. ins.LeftEdge = spos.MinX;        // these should all go into a taglist if
  388. ins.TopEdge = spos.MinY;         // you decide to substitute
  389. ins.Width = inw.Width = wide;    // OpenScreenTagList() for OpenScreen().
  390. ins.Height = inw.Height = high;
  391. ins.Depth = deep;
  392. ins.ViewModes = 0xffff & (ins.Extension[0].ti_Data = mode);
  393. ins.Extension[1].ti_Data = (ULONG)&dclip;
  394. if (iscr = OpenScreen(&ins)) {   // You might substitute OpenScreenTagList()
  395.    inw.Width = wide;
  396.    inw.Height = high;
  397.    inw.Screen = iscr;
  398.    if (!(iwnd = OpenWindow(&inw))) {
  399.       err = 1;
  400.       goto lis_done;
  401.       }
  402.    if (err = loadbody(iff, &iscr->BitMap, bmhd)) goto lis_done;
  403.    if (colortable)
  404.       if (((struct Library *)GfxBase)->lib_Version < 39)
  405.          LoadRGB4(&iscr->ViewPort, (UWORD *)colortable, colors);
  406.       else
  407.          LoadRGB32(&iscr->ViewPort, (ULONG *)colortable);
  408.    }
  409.  
  410. // The error code for extern long li_errcode may be checked here.
  411. // See getilbm_proto.h for possible values.
  412.  
  413. lis_done:
  414. if (err) {
  415.    if (iwnd) CloseWindow(iwnd);
  416.    if (iscr) CloseScreen(iscr);
  417.    iscr = NULL;
  418.    }
  419. if (colortable) free(colortable);
  420. freeIFFHandle(iff);  // IFF handle must be freed before exiting
  421. return iscr;
  422. }
  423.  
  424.  
  425. //===========================================================================
  426. // FREEILBMSCREEN
  427. // Free a screen created by loadilbmScreen().  If you saved the Window's
  428. // *original* UserPort because you needed to share another one, pass it here,
  429. // or just pass NULL if the Window still has its original UserPort.
  430. // This function is not needed if you don't need loadilbmScreen().
  431. //===========================================================================
  432. void freeilbmScreen(struct Screen *iscr, struct MsgPort *userport)
  433. {
  434. struct Window *fw = iscr->FirstWindow;
  435. if (fw) {
  436.    struct IntuiMessage *msg;
  437.    if (userport) fw->UserPort = userport;
  438.    while (msg = (struct IntuiMessage *)GetMsg(fw->UserPort))
  439.       ReplyMsg((struct Message *)msg);
  440.    CloseWindow(fw);
  441.    }
  442. CloseScreen(iscr);
  443. }
  444.  
  445. #endif  // !NOILBMSCREEN
  446.  
  447.  
  448. #ifndef ILBMSCREENONLY  // ignore next function if ILBMSCREENONLY defined
  449. //===========================================================================
  450. // LOADILBMBITMAP
  451. // Allocate a bitmap and load an ILBM file into it.  The size of the bitmap
  452. // allocated is returned in wide, high, and deep, and function returns a
  453. // pointer to the bitmap, or NULL in the case of an error.  wide, high, and
  454. // deep should all be pointers to unsigned short variables.  These variables
  455. // will be set to the dimensions of the BitMap when the function returns.
  456. // Remember to free the bitmap with freeBitMap() when you're done with it.
  457. //===========================================================================   
  458. struct BitMap
  459.     *loadilbmBitMap(char *filename, USHORT *wide, USHORT *high, USHORT *deep)
  460. {
  461. BitMapHeader *bmhd;
  462. struct BitMap *bitmap;
  463. struct IFFHandle *iff = getilbminfo(filename, wide, high, deep,
  464.                                     NULL, NULL, NULL, &bmhd);
  465. if (!iff) return NULL;
  466.  
  467. // allocate a bitmap according to the data in the bitmap header
  468. // and load the ILBM file into the bitmap
  469.  
  470. if (bitmap = getBitMap(*wide, *high, *deep, 1))
  471.    if (loadbody(iff, bitmap, bmhd)) {
  472.       freeBitMap(bitmap);                // load was unsuccessfull
  473.       bitmap = NULL;
  474.       }
  475. freeIFFHandle(iff);  // IFF handle must be freed before exiting
  476. return bitmap;
  477. }
  478. #endif  // !ILBMSCREENONLY
  479.  
  480.  
  481. //===========================================================================
  482. // GETILBMINFO -- called by loadilbmScreen() and loadilbmBitMap()
  483. // Return an IFF handle for use with loadbody() to load an ILBM body into
  484. // a bitmap, and set all the appropriate parameters to their correct values.
  485. // ALL arguments are pointers.  Only colortable, colors, and mode may be
  486. // passed as NULL.  Colormap entries are returned in *colortable (which this
  487. // function allocates), and number of colors in colors.  If <V39, colortable
  488. // is stored as the old 4-bit-per-gun style, and must be appropriately cast.
  489. // If colors is returned as 0xffff, then a colormap was not found.  If you
  490. // don't want color info, pass NULL for colors and colortable.  Likewise for
  491. // the parameter video mode.  bmhd must point to an uninitialized
  492. // BitMapHeader, which will have its contents initialized inside this
  493. // function.  The IFFHandle returned must be freed later by the calling
  494. // function using freeIFFHandle().
  495. // Upon exit, the parser will be stopped at the beginning of the BODY chunk
  496. // of the ILBM file, so that loadbody() can work properly.
  497. //===========================================================================
  498. struct IFFHandle
  499.    *getilbminfo(char *filename, USHORT *wide, USHORT *high, USHORT *deep,
  500.         WORD **colortable, USHORT *colors, unsigned long *mode, BitMapHeader **bmhd)
  501. {
  502. struct StoredProperty *sp;
  503. struct IFFHandle *iff;
  504.  
  505. if (!IFFParseBase) return NULL;
  506.  
  507. // open things
  508.  
  509. if (!(iff = AllocIFF())) return NULL;
  510. if (!(iff->iff_Stream = Open(filename, MODE_OLDFILE))) goto iffdone;
  511. InitIFFasDOS(iff);
  512. if (OpenIFF(iff, IFFF_READ)) goto iffdone;
  513. #ifdef TIMECHECK
  514. check_for_switch();
  515. #endif
  516.  
  517. // set up the parser and parse the file
  518.  
  519. if (PropChunk(iff, ID_ILBM, ID_BMHD)) goto iffdone;
  520. PropChunk(iff, ID_ILBM, ID_CMAP);
  521. PropChunk(iff, ID_ILBM, ID_CAMG);
  522. if (StopChunk(iff, ID_ILBM, ID_BODY)) goto iffdone; // stop at start of body
  523. if (ParseIFF(iff, IFFPARSE_SCAN)) goto iffdone;
  524.  
  525. #ifdef TIMECHECK
  526. check_for_switch();
  527. #endif
  528.  
  529. // extract header and determine dimensions
  530. // From modules/getbitmap.c
  531.  
  532. if (!(sp = FindProp(iff, ID_ILBM, ID_BMHD))) goto iffdone;
  533. *bmhd = (BitMapHeader *)sp->sp_Data;
  534.  
  535. *wide = RowBits((*bmhd)->w);
  536. *high = (*bmhd)->h;
  537. *deep = (*bmhd)->nPlanes;
  538.  
  539. #ifndef NOILBMSCREEN  // don't need colormap or mode info for bitmaps
  540.  
  541. // pull out colormap data that was read in if colors & coloratble was passed
  542. // Adapted from loadcmap() in modules/ilbmr.c
  543.  
  544. if (colors) {              // get colormap information
  545.    if (sp = FindProp(iff, ID_ILBM, ID_CMAP)) {
  546.       register UBYTE *rgb = sp->sp_Data;
  547.       long r, g, b;
  548.       ULONG ncheck;
  549.       USHORT i, ncolors = *colors = sp->sp_Size / sizeofColorRegister;
  550.  
  551.       if ((ncheck = 1 << (*bmhd)->nPlanes) > ncolors) ncheck = ncolors;
  552.       if (((struct Library *)GfxBase)->lib_Version >= 39) {
  553.  
  554.          // for a moment we visit an adaptation of alloccolortable()
  555.          // in modules/ilbmr.c ....
  556.  
  557.          Color32 *ct;
  558.          UWORD AllShifted = TRUE;
  559.          USHORT nc = max(ncolors, 32);
  560.  
  561.          if (!(*colortable = (WORD *)calloc( (nc*sizeof(Color32)) + (4*sizeof(WORD)), 1)))
  562.             goto errctab;
  563.          ct = (Color32 *)(*colortable + 2);
  564.          **colortable = nc;
  565.  
  566.          // now back to loadcmap() in modules/ilbmr.c ....
  567.  
  568.          i = 0;
  569.          while (ncheck--) {
  570.             ct[i].r   = r = *rgb++;
  571.             ct[i].g   = g = *rgb++;
  572.             ct[i++].b = b = *rgb++;
  573.             if ((r & 0x0f) || (g & 0x0f) || (b & 0x0f)) AllShifted = FALSE;
  574.             }
  575.          if (AllShifted && ((*bmhd)->flags & BMHDF_CMAPOK))  // shift if 4-bit
  576.             for (i = 0; i < ncolors; i++) {
  577.                ct[i].r |= (ct[i].r >> 4);
  578.                ct[i].g |= (ct[i].g >> 4);
  579.                ct[i].b |= (ct[i].b >> 4);
  580.                }
  581.          for (i = 0; i < ncolors; i++) {  // scale to 32 bits
  582.             g = ct[i].r;
  583.             ct[i].r |= ((g << 24) | (g << 16) | (g << 8));
  584.             g = ct[i].g;
  585.             ct[i].g |= ((g << 24) | (g << 16) | (g << 8));
  586.             g = ct[i].b;
  587.             ct[i].b |= ((g << 24) | (g << 16) | (g << 8));
  588.             }
  589.          }
  590.       else if (*colortable = (WORD *)calloc(ncolors, sizeof(WORD))) {
  591.          WORD *ct = *colortable;
  592.          while (ncheck--) {
  593.             r = (*rgb++ & 0xf0) << 4;
  594.             g = *rgb++ & 0xf0;
  595.             b = *rgb++ >> 4;
  596.             *(ct++) = r | g | b;
  597.             }
  598.          }
  599.       else {
  600. errctab: *colortable = NULL;
  601.          *colors = 0xffff;
  602.          }
  603.       }
  604.    else *colors = 0xffff;
  605.    }
  606.  
  607. // pull out video mode information that was read in, if mode != NULL
  608.  
  609. if (mode) {
  610.    DisplayInfoHandle displayhandle;
  611.    struct DimensionInfo dimensioninfo;
  612.    UWORD maxdepth = MAXAMDEPTH;
  613.  
  614.    // next 3 lines adapted from getdisplay() in modules/getdisplay.c
  615.  
  616.    if (RowBytes(*wide) < RowBytes((*bmhd)->pageWidth))
  617.       *wide = (*bmhd)->pageWidth;
  618.    *high = max(*high, (*bmhd)->pageHeight);
  619.  
  620.    // next 5 lines from maxdisplaydepth() in modules/getdisplay.c
  621.  
  622.    if (((struct Library *)GfxBase)->lib_Version >= 37)
  623.       if (displayhandle = FindDisplayInfo(*mode))
  624.          if (GetDisplayInfoData(displayhandle, (UBYTE *)&dimensioninfo,
  625.             sizeof(struct DimensionInfo), DTAG_DIMS, NULL))
  626.                maxdepth = dimensioninfo.MaxDepth;
  627.  
  628.    *deep = min(*deep, maxdepth);  // from getdisplay() in modules/getdisplay.c
  629.  
  630.    // Remainder of this if() block Adapted from getcamg() in modules/ilbmr.c
  631.  
  632.    *mode = 0L;
  633.    if (sp = FindProp(iff, ID_ILBM, ID_CAMG)) {
  634.       *mode = (*(unsigned long *)sp->sp_Data);
  635.       // knock bad bits out of old-style 16-bit viewmode CAMGs
  636.       if ((!(*mode & MONITOR_ID_MASK)) ||
  637.            ((*mode & EXTENDED_MODE) && (!(*mode & 0xffff0000))))
  638.          *mode &= (~(EXTENDED_MODE | SPRITES | GENLOCK_AUDIO
  639.                      | GENLOCK_VIDEO | VP_HIDE));
  640.       // check for bogus CAMG like DPaintII brushes
  641.       if ((*mode & 0xffff0000) && (!(*mode & 0x00001000))) sp = NULL;
  642.       }
  643.    if (!sp) {  // no CAMG or bad CAMG present - use computed modes
  644.       if (*wide >= 640) *mode = HIRES;
  645.       if (*high >= 400) *mode |= LACE;
  646.       if (*deep == 6) *mode |= HAM;  // or EXTRA_HALFBRITE
  647.       }
  648.    }
  649. #endif
  650.  
  651. return iff;
  652.  
  653. iffdone:
  654. if (iff) freeIFFHandle(iff);
  655. return NULL;
  656. }
  657.  
  658.  
  659. //===========================================================================
  660. // FREEIFFHANDLE -- ref: loadilbmScreen(), loadilbmBitMap(), getilbminfo()
  661. // Free the IFF Handle allocated by getilbminfo().
  662. //===========================================================================
  663. void freeIFFHandle(struct IFFHandle *iff)
  664. {
  665. CloseIFF(iff);
  666. if (iff->iff_Stream) Close(iff->iff_Stream);
  667. FreeIFF(iff);
  668. }
  669.  
  670.  
  671. //===========================================================================
  672. // LOADBODY -- called by loadilbm()
  673. // Setup to load an IFF ILBM body into a bitmap.  Nonzero return means error.
  674. // This function expects the parser to be stopped at the beginning of the
  675. // BODY chunk of a file.  Adapted from modules/ilbmr.c
  676. //===========================================================================
  677. int loadbody(struct IFFHandle *iff, struct BitMap *bitmap,BitMapHeader *bmhd)
  678. {
  679. BYTE *buffer;
  680. ULONG bufsize;
  681. LONG err = 0;
  682. register struct ContextNode *cn = CurrentChunk(iff);
  683.  
  684. if (!cn) return 1;
  685. if (cn->cn_Type != ID_ILBM || cn->cn_ID != ID_BODY) return 1;
  686. if (bitmap && bmhd) {
  687.    bufsize = MaxPackedSize(RowBytes(bmhd->w)) << 4;
  688.    if (!(buffer = AllocMem(bufsize, 0L))) return 2;
  689.    err = loadbody2(iff, bitmap, NULL, bmhd, buffer, bufsize);
  690.    }
  691. FreeMem(buffer, bufsize);
  692. return err;
  693. }
  694.  
  695.  
  696. //===========================================================================
  697. // LOADBODY2 -- called by loadbody()
  698. // Load an IFF ILBM body into a bitmap.  Nonzero return means error.
  699. // From modules/ilbmr.c
  700. //===========================================================================
  701.  
  702. #define MaxSrcPlanes (25)
  703.  
  704. int loadbody2(struct IFFHandle *iff, struct BitMap *bitmap,
  705.               BYTE *mask, BitMapHeader *bmhd, BYTE *buffer, ULONG bufsize)
  706. {
  707. register int iPlane, iRow, nEmpty;
  708. register WORD nFilled;
  709. WORD srcRowBytes = RowBytes(bmhd->w),
  710.      destRowBytes = bitmap->BytesPerRow,
  711.      destWidthBytes,   // used for width check
  712.      compression = bmhd->compression;
  713. LONG bufRowBytes = MaxPackedSize(srcRowBytes);
  714. int nRows = bmhd->h;
  715. struct ContextNode *cn = CurrentChunk(iff);
  716. UBYTE srcPlaneCnt = bmhd->nPlanes;
  717. BYTE *buf, *nullDest, *nullBuf, **pDest,
  718.      *planes[MaxSrcPlanes];   // array of ptrs to planes & mask
  719.  
  720. if (compression > cmpByteRun1) return 1;
  721. if (((struct Library *)GfxBase)->lib_Version >= 39)
  722.    destWidthBytes = RowBytes(GetBitMapAttr(bitmap, BMA_WIDTH));
  723. else
  724.    destWidthBytes = destRowBytes;
  725. if (srcRowBytes > destWidthBytes || bufsize < (bufRowBytes<<1)
  726.     || srcPlaneCnt > MaxSrcPlanes) return 1;
  727. if (nRows > bitmap->Rows) nRows = bitmap->Rows;
  728.  
  729. // Initialize array "planes" with bitmap ptrs; NULL in empty slots.
  730.  
  731. for (iPlane = 0; iPlane < bitmap->Depth; iPlane++)
  732.    planes[iPlane] = (BYTE *)bitmap->Planes[iPlane];
  733. while (iPlane < MaxSrcPlanes) planes[iPlane++] = NULL;
  734.  
  735. // copy any mask plane ptr into corresponding "planes" slot.
  736.  
  737. if (bmhd->masking == mskHasMask)
  738.    planes[srcPlaneCnt++] = mask ? mask : NULL;
  739.  
  740. // Set up a sink for dummy destination of rows from unwanted planes
  741.  
  742. nullDest = buffer;
  743. buffer += srcRowBytes;
  744. bufsize -= srcRowBytes;
  745.  
  746. // Read the BODY contents into bitmap.
  747. // De-interleave planes, decompress rows.
  748. // MODIFIES: Last iteration modifies bufsize.
  749.  
  750. buf = buffer + bufsize;  // buffer is currently empty
  751. for (iRow = nRows; iRow > 0; iRow--) {
  752.    #ifdef TIMECHECK
  753.    if (!(iRow%(40/srcPlaneCnt))) check_for_switch();  // do it every few rows
  754.    #endif
  755.    for (iPlane = 0; iPlane < srcPlaneCnt; iPlane++) {
  756.       pDest = &planes[iPlane];
  757.       if (!(*pDest)) {  // establish sink for any unwanted plane
  758.          nullBuf = nullDest;
  759.          pDest = &nullBuf;
  760.          }
  761.       // read in at least enough bytes to uncompress next row
  762.       nEmpty = buf - buffer;       // size of empty part of buffer
  763.       nFilled = bufsize - nEmpty;  // this part has data
  764.       if (nFilled < bufRowBytes) {
  765.          CopyMem(buf, buffer, nFilled);
  766.          if (nEmpty > ChunkMoreBytes(cn)) { // not enough left to fill buffer
  767.             nEmpty = ChunkMoreBytes(cn);
  768.             bufsize = nFilled + nEmpty;
  769.             }
  770.          if (ReadChunkBytes(iff, &buffer[nFilled], nEmpty) < nEmpty) return 1;
  771.  
  772.          buf = buffer;
  773.          nFilled = bufsize;
  774.      //    nEmpty = 0; // dead assignment
  775.          }
  776.       // copy uncompressed row to destination plane
  777.       if (compression == cmpNone) {
  778.          if (nFilled < srcRowBytes) return 2;
  779.          CopyMem(buf, *pDest, srcRowBytes);
  780.          buf += srcRowBytes;
  781.          *pDest += destRowBytes;
  782.          }
  783.       else {  // decompress row to destination plane
  784.          if (unpackrow(&buf, pDest, nFilled, srcRowBytes))
  785.             return 2;
  786.          else
  787.             *pDest += (destRowBytes - srcRowBytes);
  788.          }
  789.       }
  790.    }
  791. return 0;
  792. }
  793.  
  794.  
  795. //===========================================================================
  796. // UNPACKROW -- called by loadbody2()
  797. // Given pointers to pointer variables, unpack one row, updating the source
  798. // and destination pointers until it produces dstBytes bytes.
  799. // From modules/unpacker.c
  800. //===========================================================================
  801. BOOL unpackrow(BYTE **pSource, BYTE **pDest, WORD srcBytes0, WORD dstBytes0)
  802. {
  803. register BYTE *source = *pSource;
  804. register BYTE *dest = *pDest;
  805. register WORD n;
  806. register WORD srcBytes = srcBytes0, dstBytes = dstBytes0;
  807. register BYTE c;
  808. BOOL error = TRUE;  // assume error until we make it through the loop
  809. WORD minus128 = -128;  // get the compiler to generate a CMP.W
  810.  
  811. while (dstBytes > 0) {
  812.    if (--srcBytes < 0) goto errorexit;
  813.    n = *source++;
  814.    if (n >= 0) {
  815.       ++n;
  816.       if ((srcBytes -= n) < 0) goto errorexit;
  817.       if ((dstBytes -= n) < 0) goto errorexit;
  818.       do { *dest++ = *source++; } while (--n > 0);
  819.       }
  820.    else if (n != minus128) {
  821.       n = 1 - n;
  822.       if (--srcBytes < 0) goto errorexit;
  823.       if ((dstBytes -= n) < 0) goto errorexit;
  824.       c = *source++;
  825.       do { *dest++ = c; } while (--n > 0);
  826.       }
  827.    }
  828. error = FALSE;  // success!
  829.  
  830. errorexit:
  831. *pSource = source;  *pDest = dest;
  832. return error;
  833. }
  834.  
  835.  
  836. #ifdef USE_GETBM  // ignore getBitMap() if USE_GETBM not defined
  837. //=========================================================================
  838. // GETBITMAP
  839. // Allocate a bitmap according to the dimensions provided, clear it if
  840. // clear is nonzero, and return a pointer to the bitmap.  NULL is returned
  841. // if the bitmap couldn't be created.
  842. // This function has nothing to do with modules/getbitmap.c in the RKM.
  843. //=========================================================================
  844. struct BitMap *getBitMap(int wide, int high, int deep, short clear)
  845. {
  846. register short i;
  847. struct BitMap *bitmap;
  848. if (!(bitmap = (struct BitMap *)
  849.                AllocMem(sizeof(struct BitMap), MEMF_PUBLIC|MEMF_CLEAR)))
  850.    goto bitmaperr;
  851. InitBitMap(bitmap, deep, wide, high);
  852. for (i = 0; i < deep; i++) {
  853.    if (!(bitmap->Planes[i] = (PLANEPTR)AllocRaster(wide, high)))
  854.       goto bitmaperr;
  855.    if (clear) BltClear(bitmap->Planes[i], RASSIZE(wide, high), 0);
  856.    }
  857. return bitmap;
  858.  
  859. bitmaperr:
  860. freeBitMap(bitmap);
  861. return NULL;
  862. }
  863. #endif
  864.  
  865.  
  866. #ifdef USE_FREEBM  // ignore freeBitMap() if USE_FREEBM not defined
  867. //==========================================================================
  868. // FREEBITMAP
  869. // Deallocate a bitmap structure, with all its bitplanes.
  870. //==========================================================================
  871. void freeBitMap(struct BitMap *bm)
  872. {
  873. short j;
  874. if (bm) {
  875.    for (j = 0; j < bm->Depth; j++)
  876.       if (bm->Planes[j])
  877.          FreeRaster(bm->Planes[j], bm->BytesPerRow << 3, bm->Rows);
  878.    FreeMem(bm, sizeof(struct BitMap));
  879.    }
  880. }
  881. #endif
  882.